#pragma once

#include "ConsolePrerequisites.h"

struct SLexicalCastException
{
	SLexicalCastException(	const char * szSrcTypeName, 
		const char * szDstTypeName )
		: szSrcTypeName(szSrcTypeName)
		, szDstTypeName(szDstTypeName) {}

		const char * szSrcTypeName;
		const char * szDstTypeName;
};


//#define CONSOLE_CONFIG__BOOST
#ifdef CONSOLE_CONFIG__BOOST

#include <boost/lexical_cast.hpp>

template<typename Target, typename Source>
inline Target LexicalCast(const Source  & arg)
{
	try
	{
		return boost::lexical_cast<Target, Source>(arg);
	}
	catch (std::bad_cast & )
	{
		throw SLexicalCastException(typeid(Source).name(), typeid(Target).name());
	}
}

#else//!CONSOLE_CONFIG__BOOST


class CInterpreterStream
{
public:

	operator bool() const
	{
		return (!stream.fail());
	}

	template<typename Source>
		CInterpreterStream & operator << ( const Source & source )
	{
		( stream << source );
		return (*this);
	}

	template<typename Target>
		CInterpreterStream & operator >> ( Target & target )
	{
		(stream >> target);
		return (*this);
	}

	template<>
		CInterpreterStream & operator >> ( csString & target )
	{
		stream << '\0';
		stream.str().swap( target );
		return (*this);
	}

protected:
private:
	csStringStream stream;
};


template<typename Target, typename Source>
inline Target LexicalCast(const Source & arg)
{
	CInterpreterStream interpreter;
	if( interpreter << arg )
	{
		Target result;
		if ( interpreter >> result )
			return result;
	}

	throw SLexicalCastException(typeid(Source).name(), typeid(Target).name());
}



#endif // CONSOLE_CONFIG__BOOST





//////////////////////////////////////////////////////////////////////////
struct SStringToAnyTypeCastException
{
	SStringToAnyTypeCastException(	const csString & strSrcString, 
									const csString &  strDstName )
		: strSrcString(strSrcString)
		, strDstTypeName(strDstName) {}

	const csString strSrcString;
	const csString strDstTypeName;
};

template<typename Target>
inline Target LexicalCast(const csString & arg)
{
	try
	{
		return LexicalCast<Target, csString>( arg );
	}
	catch ( SLexicalCastException & )
	{
		throw SStringToAnyTypeCastException( arg, typeid(Target).name() );
	}
}





